// CyTargetLinker,
// a Cytoscape plugin to extend biological networks with regulatory interaction
//
// Copyright 2011-2013 Department of Bioinformatics - BiGCaT, Maastricht University
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
package cytargetlinker;

import java.awt.Color;

import cytargetlinker.data.RIN;
import cytoscape.visual.ArrowShape;
import cytoscape.visual.EdgeAppearanceCalculator;
import cytoscape.visual.GlobalAppearanceCalculator;
import cytoscape.visual.NodeAppearanceCalculator;
import cytoscape.visual.NodeShape;
import cytoscape.visual.VisualPropertyType;
import cytoscape.visual.VisualStyle;
import cytoscape.visual.calculators.BasicCalculator;
import cytoscape.visual.calculators.Calculator;
import cytoscape.visual.mappings.DiscreteMapping;
import cytoscape.visual.mappings.PassThroughMapping;

/**
 * visual style of the CyTargetLinker plugin
 * network nodes are grey, round nodes
 * new nodes are pink, rounded rectangle nodes
 * edges are colored based on the RIN that contained the regulatory interaction
 */
public class CyTargetLinkerVisualStyle {
	
	private NodeAppearanceCalculator nodeAppCalc;
	private EdgeAppearanceCalculator edgeAppCalc;
	private GlobalAppearanceCalculator globalAppCalc;
	private String nodeTypeAttr;
	private String networkNodeValue;
	private String newNodeValue;
	private String groupNodeValue;
	private CyTargetLinker linker;
	
	/**
	 * creates the CyTargetLinker visual style
	 */
	public VisualStyle createVisualStyle(CyTargetLinker linker) {
		this.linker = linker;
		String vsName = Preferences.getInstance().getVsName();
		nodeTypeAttr = Preferences.getInstance().getNodeTypeAttribute();
		networkNodeValue = Preferences.getInstance().getNetworkNodeValue();
		newNodeValue = Preferences.getInstance().getNewNodeValue();
		groupNodeValue = Preferences.getInstance().getGroupNodeValue();
		VisualStyle vs = new VisualStyle(vsName);
		
		nodeAppCalc = vs.getNodeAppearanceCalculator();
		edgeAppCalc = vs.getEdgeAppearanceCalculator();
		globalAppCalc = vs.getGlobalAppearanceCalculator();
				
		defineLabel();
		defineNodeShape();
		defineNodeSize();
		defineNodeColor();
		defineNodeBorder();
		defineEdgeArrow();
		defineEdgeColor();

		// Create the visual style
		vs.setEdgeAppearanceCalculator(edgeAppCalc);
		vs.setNodeAppearanceCalculator(nodeAppCalc);
		vs.setGlobalAppearanceCalculator(globalAppCalc);

		return vs;
	}

	/**
	 * defines node label for all nodes
	 */
	private void defineLabel() {
		PassThroughMapping labelMapping = new PassThroughMapping(String.class, "label");
		Calculator nodeIdCalc =  new BasicCalculator("Node Label", labelMapping, VisualPropertyType.NODE_LABEL);
		nodeAppCalc.setCalculator(nodeIdCalc);
		edgeAppCalc.setCalculator(nodeIdCalc);
	}
	
	/**
	 * defines node border for new and existing nodes
	 */
	private void defineNodeBorder() {
		DiscreteMapping nodeBorderColorMapper = new DiscreteMapping(Color.class, nodeTypeAttr);
		nodeBorderColorMapper.putMapValue(newNodeValue, Color.darkGray);
		nodeBorderColorMapper.putMapValue(networkNodeValue, Color.darkGray);
		Calculator nodeBorderColorCalc = new BasicCalculator("Node Border Color", nodeBorderColorMapper, VisualPropertyType.NODE_BORDER_COLOR);
		nodeAppCalc.setCalculator(nodeBorderColorCalc);
	}
	
	/**
	 * defines node color
	 * new node -> pink
	 * existing node -> light gray
	 * group node -> white
	 */
	private void defineNodeColor() {
		DiscreteMapping nodeColorMapping = new DiscreteMapping(Color.class, nodeTypeAttr);
		nodeColorMapping.putMapValue(newNodeValue, Color.pink);
		nodeColorMapping.putMapValue(networkNodeValue, Color.LIGHT_GRAY);
		nodeColorMapping.putMapValue(groupNodeValue, Color.WHITE);
		
		Calculator nodeColorCalc = new BasicCalculator("Node Color", nodeColorMapping, VisualPropertyType.NODE_FILL_COLOR);
		nodeAppCalc.setCalculator(nodeColorCalc);
	}
	
	/**
	 * defines node shape
	 * new nodes -> rounded rectangle
	 * existing nodes -> ellipse
	 * group nodes -> triangle
	 */
	private void defineNodeShape() {
		DiscreteMapping nodeShapeMapping = new DiscreteMapping(NodeShape.class, nodeTypeAttr);
		nodeShapeMapping.putMapValue(newNodeValue, NodeShape.ROUND_RECT);
		nodeShapeMapping.putMapValue(networkNodeValue, NodeShape.ELLIPSE);
		nodeShapeMapping.putMapValue(groupNodeValue, NodeShape.TRIANGLE);

		Calculator nodeShapeCalc = new BasicCalculator("Node Shape", nodeShapeMapping, VisualPropertyType.NODE_SHAPE);
		nodeAppCalc.setCalculator(nodeShapeCalc);
	}
	
	/**
	 * makes sure that group nodes are smaller 
	 */
	private void defineNodeSize() {
		DiscreteMapping nodeSizeMapping = new DiscreteMapping(Integer.class, nodeTypeAttr);
		nodeSizeMapping.putMapValue(groupNodeValue, 5);
		
		Calculator nodeSizeCalc = new BasicCalculator("Node Size", nodeSizeMapping, VisualPropertyType.NODE_SIZE);
		nodeAppCalc.setCalculator(nodeSizeCalc);
	}
	
	/**
	 * target interactions have an arrow shape
	 */
	private void defineEdgeArrow() {
		DiscreteMapping arrowShapeMapper = new DiscreteMapping(ArrowShape.class, "interaction");
		arrowShapeMapper.putMapValue("pp", ArrowShape.CIRCLE);
		arrowShapeMapper.putMapValue("interaction", ArrowShape.ARROW);
		for(RIN rin : linker.getRins()) {
			arrowShapeMapper.putMapValue(rin.getName(), ArrowShape.ARROW);
		}
 		arrowShapeMapper.putMapValue("Line, Arrow", ArrowShape.ARROW);
 		arrowShapeMapper.putMapValue("Line, TBar", ArrowShape.T);
  		arrowShapeMapper.putMapValue("group-connection", ArrowShape.NONE);

		Calculator arrowShapeCalc = new BasicCalculator("Arrow Shape", arrowShapeMapper, VisualPropertyType.EDGE_TGTARROW_SHAPE);
		edgeAppCalc.setCalculator(arrowShapeCalc);
	}
	
	/**
	 * defines the color of the edge and arrows
	 * everything is black except the new errors
	 * they are colored differently
	 */
	private void defineEdgeColor() {
		DiscreteMapping arrowColorMapper = new DiscreteMapping(Color.class, "interaction");

		// different Edge colors according to the RIN and preferences
		for (RIN rin : linker.getRins()) {
			arrowColorMapper.putMapValue(rin.getName(), rin.getColor());
		}

		arrowColorMapper.putMapValue("interaction", Color.BLACK);
		arrowColorMapper.putMapValue("pp", Color.BLACK);
		arrowColorMapper.putMapValue("Line, Arrow", Color.BLACK);
		arrowColorMapper.putMapValue("Line, TBar", Color.BLACK);
		arrowColorMapper.putMapValue("group-connection", Color.BLACK);

		Calculator edgeColorCalc = new BasicCalculator("Edge Color", arrowColorMapper, VisualPropertyType.EDGE_COLOR);
		Calculator arrowColorCalc = new BasicCalculator("Edge Arrow Color", arrowColorMapper, VisualPropertyType.EDGE_TGTARROW_COLOR);
		edgeAppCalc.setCalculator(edgeColorCalc);
		edgeAppCalc.setCalculator(arrowColorCalc);
	}
}